package com.leyantech.ecp.agenx.common.di;

import com.leyantech.ecp.agenx.common.misc.ZkLockUtils;

import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.spi.cluster.ClusterManager;
import io.vertx.spi.cluster.zookeeper.ZookeeperClusterManager;
import io.vertx.spi.cluster.zookeeper.impl.SubsMapHelper;
import lombok.SneakyThrows;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.TreeCache;

import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;

/**
 * @author eahau, {@literal <eahau@foxmail.com>}
 * @date 2022-11-17.
 */
public class VerticleModule extends AbstractModule {

  private final Vertx vertx;

  public VerticleModule(Vertx vertx) {
    this.vertx = vertx;
  }

  @SneakyThrows
  @Override
  protected void configure() {

    bind(Vertx.class).toInstance(vertx);
    final VertxInternal vertxInternal = (VertxInternal) this.vertx;
    bind(VertxInternal.class).toInstance(vertxInternal);
    bind(EventBus.class).toInstance(this.vertx.eventBus());

    if (vertx.isClustered()) {
      final ZookeeperClusterManager clusterManager = (ZookeeperClusterManager) vertxInternal
          .getClusterManager();
      bind(ClusterManager.class).toInstance(clusterManager);

      final Field field = ZookeeperClusterManager.class
          .getDeclaredField("lockReleaseExec");
      field.setAccessible(true);
      bind(ExecutorService.class)
          .annotatedWith(Names.named("lockReleaseExec"))
          .toInstance((ExecutorService) field.get(clusterManager));

      bind(CuratorFramework.class).toInstance(clusterManager.getCuratorFramework());

      final Field clusterNodesField = ZookeeperClusterManager.class
          .getDeclaredField("clusterNodes");
      clusterNodesField.setAccessible(true);
      bind(PathChildrenCache.class)
          .toInstance((PathChildrenCache) clusterNodesField.get(clusterManager));

      final Field subsMapHelperField = ZookeeperClusterManager.class
          .getDeclaredField("subsMapHelper");
      subsMapHelperField.setAccessible(true);

      final SubsMapHelper subsMapHelper = (SubsMapHelper) subsMapHelperField.get(clusterManager);
      final Field treeCacheField = SubsMapHelper.class.getDeclaredField("treeCache");
      treeCacheField.setAccessible(true);
      bind(TreeCache.class).toInstance((TreeCache) treeCacheField.get(subsMapHelper));

      requestStaticInjection(ZkLockUtils.class);
    }

  }

}
